home *** CD-ROM | disk | FTP | other *** search
- /*
- * syncLockStat.c --
- *
- * Maintain statistics about lock usage and lock dependencies.
- *
- * Copyright 1989 Regents of the University of California
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/sync/syncLockStat.c,v 9.1 90/10/05 17:50:34 mendel Exp $ SPRITE (Berkeley)";
- #endif /* not lint */
-
- #include <sync.h>
- #include <syncInt.h>
- #include <stdlib.h>
- #include <dbg.h>
- #include <stdio.h>
-
- /*
- * Lock registration semaphore.
- */
- Sync_Semaphore regMutex = Sync_SemInitStatic("regMutex");
- Sync_Semaphore *regMutexPtr = ®Mutex;
-
- #ifdef LOCKREG
- /*
- * Number of types registered.
- */
- static int syncTypeCount = 0;
- /*
- * Information on each type of lock registered.
- */
- static Sync_RegElement regInfo[SYNC_MAX_LOCK_TYPES];
- #endif
- static Boolean initialized = FALSE;
-
- /*
- * Keep track of locks we see with bad types. This is for debugging purposes
- * only.
- */
- #define MAX_BAD_TYPES 100
- struct BadLockType {
- Address lockPtr;
- Address pc;
- int type;
- } badType[MAX_BAD_TYPES];
-
- int badTypeCount = 0;
-
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sync_LockStatInit --
- *
- * Initializes the lock statistics routines. Must be called before
- * any kernel processes are created, and after the proc module
- * is initialized.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- void
- Sync_LockStatInit()
- {
- initialized = TRUE;
- /*
- * regMutex can't be treated like a normal lock otherwise we have a
- * chicken and the egg problem.
- */
- #ifdef LOCKREG
- regMutex.type = -1;
- #endif
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * SyncAddPriorInt --
- *
- * Adds the prior lock to the list of prior locks in the
- * current lock. Adds the current lock to the stack of
- * locks in the pcb. The current lock is registered if it hasn't
- * been already.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The lock stack in the pcb is changed.
- *
- *----------------------------------------------------------------------
- */
-
- /*ARGSUSED*/
-
- void
- SyncAddPriorInt(type, priorCountPtr, priorTypes, lockPtr, pcbPtr)
- int type;
- int *priorCountPtr;
- int *priorTypes;
- Address lockPtr;
- Proc_ControlBlock *pcbPtr;
- {
- #ifdef LOCKDEP
- int priorType;
- int i;
- Address priorLockPtr;
- static Boolean firstOverflow = TRUE;
-
- if (pcbPtr == (Proc_ControlBlock *) NIL || !initialized) {
- return;
- }
-
- Proc_GetCurrentLock(pcbPtr, &priorType, &priorLockPtr);
- if (priorType > syncTypeCount) {
- if (badTypeCount < MAX_BAD_TYPES) {
- badType[badTypeCount].lockPtr = priorLockPtr;
- badType[badTypeCount].pc = FIELD(priorLockPtr, holderPC);
- badType[badTypeCount].type = priorType;
- badTypeCount++;
- }
- }
- if (priorType >= 0) {
- for (i = 0; i < *priorCountPtr; i++) {
- if (priorType == priorTypes[i]) {
- break;
- }
- }
- if (i == *priorCountPtr && i < SYNC_MAX_PRIOR) {
- priorTypes[i] = priorType;
- *priorCountPtr += 1;
- } else if (i >= SYNC_MAX_PRIOR && firstOverflow) {
- printf("SyncAddPrior: too many prior types.\n");
- firstOverflow = FALSE;
- }
- }
- if (type == 0) {
- Sync_LockRegister(lockPtr);
- /* this routine never gets called if LOCKREG is not defined, but lint
- * will complain about this assignment anyway.
- */
- type = FIELD(lockPtr, type);
- }
- Proc_PushLockStack(pcbPtr, type, lockPtr);
- #endif
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * SyncDeleteCurrentInt --
- *
- * Removes a prior lock from the lock stack.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The lock stack in the pcb is changed.
- *
- *----------------------------------------------------------------------
- */
-
- void
- SyncDeleteCurrentInt(lockPtr, pcbPtr)
- Address lockPtr;
- Proc_ControlBlock *pcbPtr;
- {
- if (pcbPtr == (Proc_ControlBlock *) NIL || !initialized) {
- return;
- }
- Proc_RemoveFromLockStack(pcbPtr, lockPtr);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * SyncMergePriorInt --
- *
- * Merge the prior entries for a given lock with the prior entries
- * for the type. If an entry is a duplicate it is discarded, and
- * if the prior entry database overflows an error message is printed.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Stuff might be printed to the screen.
- *
- *----------------------------------------------------------------------
- */
- void
- SyncMergePriorInt(priorCount, priorTypes, regPtr)
- int priorCount;
- int *priorTypes;
- Sync_RegElement *regPtr;
- {
- int i;
- int j;
-
- if (!initialized) {
- return;
- }
- for (i = 0; i < priorCount; i++) {
- for (j = 0; j < regPtr->priorCount; j++ ) {
- if (regPtr->priorTypes[j] == priorTypes[i]) {
- break;
- }
- }
- if (j == regPtr->priorCount) {
- if (j == SYNC_MAX_PRIOR) {
- break;
- }
- regPtr->priorTypes[j] = priorTypes[i];
- regPtr->priorCount++;
- }
- }
- if (i < priorCount) {
- printf("SyncMergePriorInt: %d too many prior types.\n",
- priorCount - i);
- }
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Sync_RegisterInt --
- *
- * Registers a lock of either class (semaphore or lock). If an element
- * of the type exists then the lock is added to the linked list of
- * active locks of that type. Type equality is determined by comparing
- * the ascii name of the locks. If the lock is of a new type then an
- * element for the type is added to the list and the new lock is added
- * to the element.
- *
- * This routine should be called prior to using the lock.
- *
- * Results:
- * None.
- *
- * Side effects:
- * A new element may be added to regQueue.
- *
- *----------------------------------------------------------------------
- */
-
- #ifndef LOCKREG
- /* ARGSUSED */
- #endif
-
- void
- Sync_RegisterInt(lock)
- Address lock; /*lock to be registered */
- {
- #ifdef LOCKREG
- List_Links *lockQueuePtr;
- Sync_RegElement *regPtr;
- char *name;
- static int newTypeGenerator = 1;
- int *typePtr;
- Sync_ListInfo *listInfoPtr;
- int i;
-
- typePtr = &(FIELD(lock,type)) ;
- if (*typePtr != 0) {
- return;
- }
- name = FIELD(lock,name);
- if (name == (char *) 0) {
- return;
- }
- if (initialized) {
- MASTER_LOCK(regMutexPtr);
- }
- if (*typePtr != 0 || FIELD(lock, name) == (char *) 0) {
- goto exit;
- }
- listInfoPtr = &(FIELD(lock,listInfo));
- regPtr = (Sync_RegElement *) NIL;
- for (i = 0; i < syncTypeCount; i++) {
- if (!strcmp(name, regInfo[i].name)) {
- regPtr = ®Info[i];
- regPtr->activeLockCount++;
- break;
- }
- }
- if (regPtr == (Sync_RegElement *) NIL) {
- if (syncTypeCount >= SYNC_MAX_LOCK_TYPES) {
- printf("Sync_RegisterAnyLock: too many lock types.\n");
- goto exit;
- }
- regPtr = ®Info[syncTypeCount];
- regPtr->name = name;
- regPtr->type = newTypeGenerator++;
- regPtr->activeLockCount = 1;
- regPtr->deadLockCount = 0;
- regPtr->hit = 0;
- regPtr->miss = 0;
- regPtr->priorCount = 0;
- List_Init((List_Links *) &(regPtr->activeLocks));
- syncTypeCount++;
- }
- lockQueuePtr = (List_Links *) &(regPtr->activeLocks);
- if (listInfoPtr == (Sync_ListInfo *) lockQueuePtr->prevPtr) {
- panic("Trying to reregister a lock.\n");
- }
- regPtr->class = ((Sync_Lock *) lock)->class;
- *typePtr = regPtr->type;
- listInfoPtr->lock = lock;
- List_InitElement((List_Links *) listInfoPtr);
- List_Insert((List_Links *) listInfoPtr,
- LIST_ATREAR(lockQueuePtr));
- exit:
- if (initialized) {
- MASTER_UNLOCK(regMutexPtr);
- }
- #endif /* LOCKREG */
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Sync_CheckoutInt --
- *
- * Used to de-register ("checkout") a lock when it is being
- * deallocated. It is removed from the linked list of active locks for
- * the type, and its statistics are merged with the running total in
- * the type element.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- #ifndef LOCKREG
- /*ARGSUSED*/
- #endif
-
- void
- Sync_CheckoutInt(lock)
- Address lock; /*lock to be registered */
- {
- #ifdef LOCKREG
- List_Links *lockQueuePtr;
- List_Links *itemPtr;
- Sync_RegElement *regPtr;
- int type;
-
- if (initialized) {
- MASTER_LOCK(regMutexPtr);
- }
- type = FIELD(lock,type);
- if (type <= 0) {
- goto exit;
- }
- regPtr = ®Info[type-1];
- lockQueuePtr = (List_Links *) &(regPtr->activeLocks);
- LIST_FORALL(lockQueuePtr, itemPtr) {
- if (((Sync_ListInfo *) itemPtr)->lock == lock) {
- List_Remove(itemPtr);
- regPtr->activeLockCount--;
- regPtr->deadLockCount++;
- SyncAddLockStats(regPtr, ((Sync_ListInfo *) itemPtr)->lock);
- goto exit;
- }
- }
- exit:
- if (initialized) {
- MASTER_UNLOCK(regMutexPtr);
- }
- #endif /* LOCKREG */
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Sync_GetLockStats --
- *
- * Prints out the locking statistics.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- #ifndef LOCKREG
- /*ARGSUSED*/
- #endif
-
- ReturnStatus
- Sync_GetLockStats(size, argPtr)
- int size;
- Address argPtr;
-
- {
-
- #ifdef LOCKREG
- List_Links *lockQueuePtr;
- List_Links *itemPtr;
- Sync_RegElement *regPtr;
- Sync_RegElement tempReg;
- int i;
- int j;
- Sync_LockStat *statArray;
- int index;
- ReturnStatus status;
-
- if (size <= 0) {
- return SUCCESS;
- }
- if (size < syncTypeCount) {
- return FAILURE;
- }
- statArray = (Sync_LockStat *) malloc(size * sizeof(Sync_LockStat));
- MASTER_LOCK(regMutexPtr);
- bzero((char *) statArray, size * sizeof(Sync_LockStat));
- for (i = 0; i < syncTypeCount; i++) {
- regPtr = ®Info[i];
- bcopy((char *) regPtr, (char *) &tempReg, sizeof(Sync_RegElement));
- lockQueuePtr = (List_Links *) &(regPtr->activeLocks);
- LIST_FORALL(lockQueuePtr, itemPtr) {
- SyncAddLockStats(&tempReg, ((Sync_ListInfo *) itemPtr)->lock);
- }
- index = regPtr->type -1;
- statArray[index].inUse = 1;
- statArray[index].class = (regPtr->class == SYNC_SEMAPHORE) ? 0 : 1;
- statArray[index].hit = tempReg.hit;
- statArray[index].miss = tempReg.miss;
- statArray[index].activeCount = regPtr->activeLockCount;
- statArray[index].deadCount = regPtr->deadLockCount;
- strncpy(statArray[index].name, regPtr->name, 30);
- statArray[index].name[29] = '\0';
- statArray[index].priorCount = tempReg.priorCount;
- for (j = 0; j < tempReg.priorCount; j++) {
- statArray[index].priorTypes[j] = tempReg.priorTypes[j];
- }
- for (j = 0; j < mach_NumProcessors; j++) {
- statArray[index].spinCount += sync_Instrument[j].spinCount[index+1];
- }
- }
- Vm_CopyOut(sizeof(Sync_LockStat) * size, (Address)statArray, argPtr);
- MASTER_UNLOCK(regMutexPtr);
- free((Address) statArray);
- return (SUCCESS);
- #else /* LOCKREG */
- return (FAILURE);
- #endif /* LOCKREG */
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Sync_ResetLockStats --
- *
- * Resets all the locking statistics.
- *
- * Results:
- * FAILURE if an error occurred, SUCCESS otherwise.
- *
- * Side effects:
- * Hit and miss counts are reset, count of prior lock types is
- * reset.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- Sync_ResetLockStats()
- {
- #ifdef LOCKREG
- int i;
- int j;
- List_Links *lockQueuePtr;
- List_Links *itemPtr;
- Sync_RegElement *regPtr;
-
- MASTER_LOCK(regMutexPtr);
- for (i = 0; i < syncTypeCount; i++) {
- regPtr = ®Info[i];
- lockQueuePtr = (List_Links *) &(regPtr->activeLocks);
- LIST_FORALL(lockQueuePtr, itemPtr) {
- *(&FIELD(((Sync_ListInfo *) itemPtr)->lock, hit)) = 0;
- *(&FIELD(((Sync_ListInfo *) itemPtr)->lock, miss)) = 0;
- #ifdef LOCKDEP
- *(&FIELD(((Sync_ListInfo *) itemPtr)->lock, priorCount)) = 0;
- #endif
- }
- regPtr->hit = 0;
- regPtr->miss = 0;
- regPtr->priorCount = 0;
- }
- for (i = 0; i < mach_NumProcessors; i++) {
- for (j = 0; j < syncTypeCount+1; j++) {
- sync_Instrument[i].spinCount[j] = 0;
- }
- sync_Instrument[i].sched_MutexMiss = 0;
- }
- MASTER_UNLOCK(regMutexPtr);
- return SUCCESS;
- #else /* LOCKREG */
- return (FAILURE);
- #endif /* LOCKREG */
-
- }
-